package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.NivelDAO;
import pe.com.casadesign.domain.ListaNivelColor;
import pe.com.casadesign.domain.ListaNivelMaterial;
import pe.com.casadesign.domain.ListaNivelProducto;
import pe.com.casadesign.domain.ListaNivelTipo;
import pe.com.casadesign.domain.Nivel;
import pe.com.casadesign.domain.NivelColor;
import pe.com.casadesign.domain.NivelMaterial;
import pe.com.casadesign.domain.NivelProducto;
import pe.com.casadesign.domain.NivelTipo;

/**
 * Implementacion de NivelDAO.
 * 
 * @author Gustavo Susano
 * 
 */
@Repository
public class NivelDAOImpl implements NivelDAO {
private static final Logger logger = LoggerFactory.getLogger(ProductoDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_REGISTRAR_NIVEL_PRODUCTO = "SP_REGISTRAR_NIVELPROD";
	private static String SP_MODIFICAR_NIVEL_PRODUCTO = "SP_MODIFICAR_NIVELPROD";
	private static String SP_REGISTRAR_NIVEL_TIPO_PRODUCTO = "SP_REGISTRAR_NIVELTIPO";
	private static String SP_MODIFICAR_NIVEL_TIPO_PRODUCTO = "SP_MODIFICAR_NIVELTIPO";
	private static String SP_REGISTRAR_NIVEL_MATERIAL = "SP_REGISTRAR_NIVELMATERIAL";
	private static String SP_MODIFICAR_NIVEL_MATERIAL = "SP_MODIFICAR_NIVELMATERIAL";
	private static String SP_REGISTRAR_NIVEL_COLOR = "SP_REGISTRAR_NIVELCOLOR";
	private static String SP_MODIFICAR_NIVEL_COLOR = "SP_MODIFICAR_NIVELCOLOR";
	
	private static String SP_LISTAR_NIVELES = "SP_LISTAR_NIVELES";
		
	// Parametros de Entrada
	private static String PARAM_DESCRIPCION = "p_descripcion";
	private static String PARAM_CODNIVELPROD = "p_codnivelprod";
	private static String PARAM_CODNIVELTIPO = "p_codniveltipo";
	private static String PARAM_CODNIVELMATERIAL = "p_codnivelmaterial";
	private static String PARAM_CODNIVELCOLOR = "p_codnivelcolor";
	private static String PARAM_ESTADO = "p_estado";
		
	// Parametros de Salida
	private static String DESCRIPCION = "DESCRIPCION";
	private static String CODNIVELPROD = "CODNIVELPROD";
	private static String CODNIVELTIPO = "CODNIVELTIPO";
	private static String CODNIVELMATERIAL = "CODNIVELMATERIAL";
	private static String CODNIVELCOLOR = "CODNIVELCOLOR";
	private static String ESTADO ="ESTADO";

	private static String LISTA_NIVEL_PRODUCTO = "LISTADO_NIVEL_PRODUCTO";
	private static String LISTA_NIVEL_TIPO = "LISTA_NIVEL_TIPO";
	private static String LISTA_NIVEL_MATERIAL = "LISTA_NIVEL_MATERIAL";
	private static String LISTA_NIVEL_COLOR = "LISTA_NIVEL_COLOR";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;

	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
	
	@Override
	public Nivel listarNiveles(){
		logger.info("listarNiveles");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_NIVELES).
	    						  returningResultSet(LISTA_NIVEL_PRODUCTO, new RowMapper<NivelProducto>(){
									@Override
									public NivelProducto mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final NivelProducto nivelProducto = new NivelProducto();
								        nivelProducto.setCodigo(rs.getInt(CODNIVELPROD));
								        nivelProducto.setDescripcion(rs.getString(DESCRIPCION));
								        nivelProducto.setEstado(rs.getString(ESTADO));
								        return nivelProducto;
								    }
	    						   }
								  ).
								  returningResultSet(LISTA_NIVEL_TIPO, new RowMapper<NivelTipo>(){
										@Override
										public NivelTipo mapRow(final ResultSet rs, final int numRow) throws SQLException
									    {
									        final NivelTipo nivelTipo = new NivelTipo();
									        nivelTipo.setCodigo(rs.getInt(CODNIVELTIPO));
									        nivelTipo.setCodNivelProducto(rs.getInt(CODNIVELPROD));
									        nivelTipo.setDescripcion(rs.getString(DESCRIPCION));
									        nivelTipo.setEstado(rs.getString(ESTADO));
									        return nivelTipo;
									    }
		    						  }
								  ).
								  returningResultSet(LISTA_NIVEL_MATERIAL, new RowMapper<NivelMaterial>(){
										@Override
										public NivelMaterial mapRow(final ResultSet rs, final int numRow) throws SQLException
									    {
									        final NivelMaterial nivelMaterial = new NivelMaterial();
									        nivelMaterial.setCodigo(rs.getInt(CODNIVELMATERIAL));
									        nivelMaterial.setCodNivelProducto(rs.getInt(CODNIVELPROD));
									        nivelMaterial.setDescripcion(rs.getString(DESCRIPCION));
									        nivelMaterial.setEstado(rs.getString(ESTADO));
									        return nivelMaterial;
									    }
		    						  }
								  ).
								  returningResultSet(LISTA_NIVEL_COLOR, new RowMapper<NivelColor>(){
										@Override
										public NivelColor mapRow(final ResultSet rs, final int numRow) throws SQLException
									    {
									        final NivelColor nivelColor = new NivelColor();
									        nivelColor.setCodigo(rs.getInt(CODNIVELCOLOR));
									        nivelColor.setCodNivelProducto(rs.getInt(CODNIVELPROD));
									        nivelColor.setDescripcion(rs.getString(DESCRIPCION));
									        nivelColor.setEstado(rs.getString(ESTADO));
									        return nivelColor;
									    }
		    						  }
								  );

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute();

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<NivelProducto> listaNivelProducto = (List<NivelProducto>)data.get(LISTA_NIVEL_PRODUCTO);
        
		@SuppressWarnings("unchecked")
		List<NivelTipo> listaNivelTipo = (List<NivelTipo>)data.get(LISTA_NIVEL_TIPO);
		
		@SuppressWarnings("unchecked")
		List<NivelMaterial> listaNivelMaterial = (List<NivelMaterial>)data.get(LISTA_NIVEL_MATERIAL);
		
		@SuppressWarnings("unchecked")
		List<NivelColor> listaNivelColor = (List<NivelColor>)data.get(LISTA_NIVEL_COLOR);
		
		// Instanciando objeto Nivel
        Nivel nivel = new Nivel();
        
        // Estableciendo resultado al objeto listaNivelProductoResultado
        ListaNivelProducto listaNivelProductoResultado = new ListaNivelProducto();
        listaNivelProductoResultado.setLista(listaNivelProducto);
        
        // Estableciendo resultado al objeto listaNivelTipoResultado
        ListaNivelTipo listaNivelTipoResultado = new ListaNivelTipo();
        listaNivelTipoResultado.setLista(listaNivelTipo);
        
        // Estableciendo resultado al objeto listaNivelMaterialResultado
        ListaNivelMaterial listaNivelMaterialResultado = new ListaNivelMaterial();
        listaNivelMaterialResultado.setLista(listaNivelMaterial);
        
        // Estableciendo resultado al objeto listaNivelColorResultado
        ListaNivelColor listaNivelColorResultado = new ListaNivelColor();
        listaNivelColorResultado.setLista(listaNivelColor);
        
        // Estableciendo listas de niveles
        nivel.setListaNivelProducto(listaNivelProductoResultado);
        nivel.setListaNivelTipo(listaNivelTipoResultado);
        nivel.setListaNivelMaterial(listaNivelMaterialResultado);
        nivel.setListaNivelColor(listaNivelColorResultado);
        
        if (logger.isDebugEnabled() && listaNivelProducto != null)
        {
            logger.debug("sizeNivelProd=" + listaNivelProducto.size());
        }
        
        if (logger.isDebugEnabled() && listaNivelTipo != null)
        {
            logger.debug("sizeNivelTipo=" + listaNivelTipo.size());
        }
        
        if (logger.isDebugEnabled() && listaNivelMaterial != null)
        {
            logger.debug("sizeNivelMaterial=" + listaNivelMaterial.size());
        }
        
        if (logger.isDebugEnabled() && listaNivelColor != null)
        {
            logger.debug("sizeNivelColor=" + listaNivelColor.size());
        }
        
        return nivel;
	}
	
	@Override
	public boolean registrarNivelProducto(NivelProducto nivelProducto) {
		logger.info("registrarNivelProducto");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_NIVEL_PRODUCTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_DESCRIPCION, nivelProducto.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelProducto.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODNIVELPROD));

	    // Obteniendo codigo de nivel producto
	    int codigonivelProducto = (Integer)data.get(PARAM_CODNIVELPROD);

	    // Estableciendo codigo generado al objeto nivelProducto
	    nivelProducto.setCodigo(codigonivelProducto);
	     
	    return resultado > 0;
	}
	
	@Override
	public boolean modificarNivelProducto(NivelProducto nivelProducto) {
		logger.info("modificarNivelProducto");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_NIVEL_PRODUCTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODNIVELPROD, nivelProducto.getCodigo())
	    								.addValue(PARAM_DESCRIPCION, nivelProducto.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelProducto.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return resultado > 0;
	}
	
	
	@Override
	public boolean registrarNivelTipo(NivelTipo nivelTipo) {
		logger.info("registrarNivelTipo");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_NIVEL_TIPO_PRODUCTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	                                    .addValue(PARAM_CODNIVELPROD, nivelTipo.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelTipo.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelTipo.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODNIVELTIPO));

	    // Obteniendo codigo de nivel producto
	    int codigoniveltipoProducto = (Integer)data.get(PARAM_CODNIVELTIPO);

	    // Estableciendo codigo generado al objeto nivelProducto
	    nivelTipo.setCodigo(codigoniveltipoProducto);
	     
	    return resultado > 0;
	}
	
	@Override
	public boolean modificarNivelTipo(NivelTipo nivelTipo) {
		logger.info("modificarNivelTipo");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_NIVEL_TIPO_PRODUCTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	                                    .addValue(PARAM_CODNIVELTIPO, nivelTipo.getCodigo())
	    								.addValue(PARAM_CODNIVELPROD, nivelTipo.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelTipo.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelTipo.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return resultado > 0;
	}
	
	@Override
	public boolean registrarNivelMaterial(NivelMaterial nivelMaterial) {
		logger.info("registrarNivelMaterial");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_NIVEL_MATERIAL);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODNIVELPROD, nivelMaterial.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelMaterial.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelMaterial.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODNIVELMATERIAL));

	    // Obteniendo codigo de nivel producto
	    int codigonivelMaterial = (Integer)data.get(PARAM_CODNIVELMATERIAL);

	    // Estableciendo codigo generado al objeto nivelMaterial
	    nivelMaterial.setCodigo(codigonivelMaterial);
	     
	    return resultado > 0;
	}
	
	@Override
	public boolean modificarNivelMaterial(NivelMaterial nivelMaterial) {
		logger.info("modificarNivelMaterial");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_NIVEL_MATERIAL);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODNIVELMATERIAL, nivelMaterial.getCodigo())
	    								.addValue(PARAM_CODNIVELPROD, nivelMaterial.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelMaterial.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelMaterial.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return resultado > 0;
	}
	
	@Override
	public boolean registrarNivelColor(NivelColor nivelColor){
		logger.info("registrarNivelColor");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_NIVEL_COLOR);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODNIVELPROD, nivelColor.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelColor.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelColor.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODNIVELCOLOR));

	    // Obteniendo codigo de nivel producto
	    int codigonivelColor = (Integer)data.get(PARAM_CODNIVELCOLOR);

	    // Estableciendo codigo generado al objeto nivelMaterial
	    nivelColor.setCodigo(codigonivelColor);
	     
	    return resultado > 0;
	}
	
	@Override
	public boolean modificarNivelColor(NivelColor nivelColor){
		logger.info("modificarNivelColor");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_NIVEL_COLOR);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODNIVELCOLOR, nivelColor.getCodigo())
	    								.addValue(PARAM_CODNIVELPROD, nivelColor.getCodNivelProducto())
	    								.addValue(PARAM_DESCRIPCION, nivelColor.getDescripcion())
	    								.addValue(PARAM_ESTADO, nivelColor.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    return resultado > 0;
	}
}